﻿#region License
/*
Copyright (c) <2012> <Nercoding>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Original Code by Gastric of Dawnsong
 */
#endregion
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using AC2_MultiClient.Managers;

namespace AC2_MultiClient.Forms
{
    public partial class DirectoryForm : Form
    {
        #region OnLoad
        /*
         * This form handles copying a valid ac2 directory
         * into a new directory so we can use it to log on 
         * another client, as ac2 will give an error of file in use
         * if we try to run it twice from the same directory.
         * 
         * It also handles adding or removing directories from our main xml file
         */
        public DirectoryForm()
        {
            InitializeComponent();
        }
        /// <summary>
        /// What actions to complete when this form loads
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DirectoryForm_Load(object sender, EventArgs e)
        {
            if (XmlManager.Directories.Count == 0)
            {
                // We have no valid game client directories
                this.button1.Text = "Add Ac2 Directory";
            }
            else
            {
                // Load all our Directories from our xml file.
                foreach (string d in XmlManager.Directories)
                {
                    try
                    {
                        FileInfo file = new FileInfo(d);
                        DirectoriesList.Items.Add(file.Directory.FullName);
                    }
                    catch { }
                }
            }
        }
        #endregion
        #region CopyTools
        /// <summary>
        /// Checks if a directory has an ac2launcher and is a valid ac2 dir
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private bool IsValidDirectory(string path)
        {
            string[] files = Directory.GetFiles(path, "ac2launcher.exe");
            if (files.Length > 0) { return true; }
            else { return false; }
        }
        /// <summary>
        /// Generates a list of files to copy from a known good directory
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private List<string> GenerateCopyList(string path)
        {
            /* We dont want to copy all directories inside the install directory
             * Just in case thats where the user is making new directories
             * Meaning C:\Games\Turbine\Asheron's Call 2\2 is a second directory
             * probably containing all the copied files, so we dont want to copy that too
             * as it can eventually become a huge redundent repeating nitemare.
             * So we will just copy the things we know needs copied.
             * DIRECTORIES
             * Content
             * Controls
             * keymap
             * Plugins
             * And then all the files
             */
            List<string> AllFiles = new List<string>();
            string[] Content = Directory.GetFiles(Path.Combine(path, "Content"), "*", SearchOption.AllDirectories);
            string[] Controls = Directory.GetFiles(Path.Combine(path, "Controls"), "*", SearchOption.AllDirectories);
            string[] Keymap = Directory.GetFiles(Path.Combine(path, "keymap"), "*", SearchOption.AllDirectories);
            string[] Plugins = Directory.GetFiles(Path.Combine(path, "Plugins"), "*", SearchOption.AllDirectories);
            string[] Others = Directory.GetFiles(path, "*");
            foreach (string s in Content) { AllFiles.Add(s); }
            foreach (string s in Controls) { AllFiles.Add(s); }
            foreach (string s in Keymap) { AllFiles.Add(s); }
            foreach (string s in Plugins) { AllFiles.Add(s); }
            foreach (string s in Others) { AllFiles.Add(s); }
            return AllFiles;
        }
        /// <summary>
        /// Messy way to duplicate our ac2 directory from a good known copy.
        /// </summary>
        /// <param name="toPath">The new Directory Chosen</param>
        /// <param name="fileList">A list of files from a good known copy.</param>
        public void CopyFiles(string toPath, List<string> fileList)
        {
            if (!Directory.Exists(toPath)) { return; }
            int TotalFiles = fileList.Count;

            foreach (string s in fileList)
            {
                FileInfo f = new FileInfo(s);
                /* We have different types of files here
                 * Content/*
                 * Controls/*
                 * keymap/*
                 * Plugins/*
                 * and the rest
                 */
                int Content = f.FullName.IndexOf("Content");
                int Controls = f.FullName.IndexOf("Controls");
                int keymap = f.FullName.IndexOf("keymap");
                int Plugins = f.FullName.IndexOf("Plugins");
                // make the directories
                try
                {
                    Directory.CreateDirectory(Path.Combine(toPath, "Content\\Gallery"));
                    Directory.CreateDirectory(Path.Combine(toPath, "Controls"));
                    Directory.CreateDirectory(Path.Combine(toPath, "keymap"));
                    Directory.CreateDirectory(Path.Combine(toPath, "Plugins"));
                }
                catch
                {
                    // Cant do it.
                    MessageBox.Show("Unable to copy to " + toPath, "Error in Copy!",
                        MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    return;
                }
                // Turn on Progress bar
                ActivateProgressBar(TotalFiles);
                ActivateLabel(true);
                try
                {
                    if (f.FullName.Contains("Content\\"))
                    {
                        string newFile = Path.Combine(toPath, f.FullName.Substring(Content));
                        f.CopyTo(newFile);
                        UpdateLabel(newFile);
                        PerformStep();
                    }
                    else if (f.FullName.Contains("Controls\\"))
                    {
                        string newFile = Path.Combine(toPath, f.FullName.Substring(Controls));
                        f.CopyTo(newFile);
                        UpdateLabel(newFile);
                        PerformStep();
                    }
                    else if (f.FullName.Contains("keymap\\"))
                    {
                        string newFile = Path.Combine(toPath, f.FullName.Substring(keymap));
                        f.CopyTo(newFile);
                        UpdateLabel(newFile);
                        PerformStep();
                    }
                    else if (f.FullName.Contains("Plugins\\"))
                    {
                        string newFile = Path.Combine(toPath, f.FullName.Substring(Plugins));
                        f.CopyTo(newFile);
                        UpdateLabel(newFile);
                        PerformStep();
                    }
                    else
                    {
                        // Regular file
                        string newFile = Path.Combine(toPath, f.FullName.Split('\\').Last());
                        f.CopyTo(newFile);
                        UpdateLabel(newFile);
                        PerformStep();
                    }
                }
                catch 
                { 
                    MessageBox.Show("Unable to Copy Directory.", "Error in Copy!", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    // Turn off our label
                    ActivateLabel(false);
                    // Turn off our progressbar
                    ToggleProgressBar(false);
                    return;
                }
            }
            UpdateLabel("Copy Completed.");
            // Add this new Directory to our Directory list, and save it in our xml
            XmlManager.AddDirectoryLocation(Path.Combine(toPath, "ac2launcher.exe"));
            AddDirectoryToList(toPath);
            // Turn on our ok button
            ToggleCloseButton(true);
        }
        /// <summary>
        /// Deletes a directory
        /// </summary>
        /// <param name="path"></param>
        private void RemoveDirectory(string path, int index)
        {
            try
            {
                if (Directory.Exists(path)) { Directory.Delete(path, true); }
                // Remove it from our list
                DirectoriesList.Items[index].Remove();
            }
            catch { }
        }
        /// <summary>
        /// Perform a Progress bar step
        /// </summary>
        private void PerformStep()
        {
            if (progressBar.InvokeRequired)
            {
                progressBar.Invoke((MethodInvoker)
                    delegate
                    {
                        progressBar.PerformStep();
                    });
            }
        }
        /// <summary>
        /// Update our label text
        /// </summary>
        /// <param name="info">The Text to Update.</param>
        private void UpdateLabel(string info)
        {
            if (this.copyLabel.InvokeRequired)
            {
                this.copyLabel.Invoke((MethodInvoker)
                    delegate
                    {
                        this.copyLabel.Text = info;
                    });
            }
        }
        /// <summary>
        /// Toggles our Label text on or off
        /// </summary>
        /// <param name="TotalFiles"></param>
        private void ActivateProgressBar(int TotalFiles)
        {
            if (this.progressBar.InvokeRequired)
            {
                this.progressBar.Invoke((MethodInvoker)
                    delegate
                    {
                        this.progressBar.Visible = true;
                        this.progressBar.Minimum = 1;
                        this.progressBar.Maximum = TotalFiles;
                        this.progressBar.Step = 1;
                    });
            }
        }
        /// <summary>
        /// Toggle our Close form button off or on
        /// </summary>
        /// <param name="toggle"></param>
        private void ToggleCloseButton(bool toggle)
        {
            if (this.btn_OK.InvokeRequired)
            {
                this.btn_OK.Invoke((MethodInvoker)
                    delegate
                    {
                        this.btn_OK.Visible = toggle;
                    });
            }
        }
        /// <summary>
        /// Toggles our progress bar on or off
        /// </summary>
        /// <param name="toggle"></param>
        private void ToggleProgressBar(bool toggle)
        {
            if (this.progressBar.InvokeRequired)
            {
                this.progressBar.Invoke((MethodInvoker)
                    delegate
                    {
                        this.progressBar.Visible = toggle;
                    });
            }
        }
        /// <summary>
        /// Activates our label
        /// </summary>
        /// <param name="toggle"></param>
        private void ActivateLabel(bool toggle)
        {
            if (this.copyLabel.InvokeRequired)
            {
                this.copyLabel.Invoke((MethodInvoker)
                    delegate
                    {
                        this.copyLabel.Visible = toggle;
                    });
            }
        }
        /// <summary>
        /// Adds a Directory to our list.
        /// </summary>
        /// <param name="dir"></param>
        private void AddDirectoryToList(string dir)
        {
            if (DirectoriesList.InvokeRequired)
            {
                DirectoriesList.Invoke((MethodInvoker)
                    delegate
                    {
                        DirectoriesList.Items.Add(dir);
                    });
            }
        }
        #endregion
        #region Buttons
        /// <summary>
        /// Our close form button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Removes a Directory from our list.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            // get the selection
            if (DirectoriesList.SelectedItems[0].Text == string.Empty) { return; }
            // Ok remove it from our list.
            string toRemove = DirectoriesList.SelectedItems[0].Text + "\\ac2launcher.exe";
            DialogResult result = MessageBox.Show(
                "Would you like to remove the entire directory from your system ?",
                "Remove all Files ?",
                MessageBoxButtons.YesNoCancel,
                MessageBoxIcon.Question);
            if (result == System.Windows.Forms.DialogResult.Yes)
            {
                if (DirectoriesList.Items.Count == 1)
                {
                    MessageBox.Show("Unable to remove root Directory!", "Unable to Remove Directory!",
                        MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    return;
                }
                RemoveDirectory(DirectoriesList.SelectedItems[0].Text, DirectoriesList.SelectedItems[0].Index);
                XmlManager.RemoveDirectoryLocation(toRemove);
            }
            else if (result == System.Windows.Forms.DialogResult.No)
            {

                if (DirectoriesList.Items.Count == 1)
                {
                    MessageBox.Show("Unable to remove root Directory!", "Unable to Remove Directory!",
                        MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    return;
                }
                // Just remove it from our list
                DirectoriesList.SelectedItems[0].Remove();
                XmlManager.RemoveDirectoryLocation(toRemove);
            }
        }
        /// <summary>
        /// Our Copy Directory Button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            // First we need to make sure we have a directory to copy from
            if (XmlManager.Directories.Count == 0)
            {
                // We dont have any, so ask to select it
                SelectAC2Dir.Description = "Select a Valid Asheron's Call 2 Install Directory.";
                DialogResult result = SelectAC2Dir.ShowDialog();
                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    // See if its valid
                    if (IsValidDirectory(SelectAC2Dir.SelectedPath))
                    {
                        // Then add it
                        XmlManager.AddDirectoryLocation(SelectAC2Dir.SelectedPath + "\\ac2launcher.exe");
                        DirectoriesList.Items.Add(SelectAC2Dir.SelectedPath + "\\ac2launcher.exe");
                    }
                }
            }

            // So now we want to copy it to a new Directory so we can use it to multi log.
            SelectAC2Dir.Description = "Select a new location to copy AC2 install too.";
            SelectAC2Dir.ShowNewFolderButton = true;
            DialogResult result2 = SelectAC2Dir.ShowDialog();
            if (result2 == System.Windows.Forms.DialogResult.OK)
            {
                // Get the new path
                if (!Directory.Exists(SelectAC2Dir.SelectedPath)) { Directory.CreateDirectory(SelectAC2Dir.SelectedPath); }
                // Generate a copy list from a known source
                FileInfo f = new FileInfo(XmlManager.Directories[0]);
                List<string> toCopy = GenerateCopyList(f.Directory.FullName);

                // Copy using a background thread.
                System.Threading.Thread thread = new System.Threading.Thread(delegate()
                {
                    CopyFiles(SelectAC2Dir.SelectedPath, toCopy);
                });
                thread.IsBackground = true;
                thread.Start();
                // So now we need to change our button text back to copy, because we
                // had no valid directories so it was changed
                if (button1.InvokeRequired)
                {
                    button1.Invoke((MethodInvoker)
                    delegate
                    {
                        button1.Text = "Copy to New Directory";
                    });
                }
            }
        }
        #endregion
    }
}
